package controller.managedBeans;

import java.io.Serializable;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.*;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import model.entities.*;
import model.dao.*;

@ManagedBean(name = "saleBacking")
@SessionScoped
public class SaleBacking  implements Serializable{

/*
 * this is the manged bean it will contains all objects needed to run the UI
 * It will need the following
 * 
 * 1- Will will communicate with the model bussiniss logic throw inject the stateless EJB3.1 to the managed bean
 * 2- make this bean in a session scope or in a view scope. (test the deffirance and performance) 
 * 3- this bean is a representation for Master Detail design the master is an object of SALE entity and
 *    to insert detail , I will create list of details every one has a reference for the master
 *    Then I will make master.setDetails then save the master object which will save the details also
 * 4- initially, empty master will be created, and current date will be inserted.
 * 5- in details, a list on one empty detail is created by default. 	 
 */

    private static final long serialVersionUID = 1L;
	   
    //inject the needed EJB
	@EJB
    private SaleDao saleFacade;
	
	@EJB
    private ItemsDao itemsFacade;
	
	@EJB
    private UsersDao usersFacade ;
	
	@EJB
    private NameDao nameFacade ;
	
    
	// the master object
	private Sale sale = null ;
	
	// the detail object
	private SaleLine saleLine = null;
	
	//the details List
	private List<SaleLine> salesLines ;
	
	//List of items to be added to the list Item (LOV)
	private List<Item> items ;
	private String saleSavingStatus = "false";

	private DataModel<SaleLine> model ;
	private SaleLine currentSaleLine ;
	
    private Item item = new Item();
    private boolean edit;
    private float total ;
    private int view_no_counter = 1 ;
    
    @Size(min=3, max=12)
    private String name = null;
    @Pattern(regexp = "^[\\w\\-]([\\.\\w])+[\\w]+@([\\w\\-]+\\.)+[a-zA-Z]{2,4}$" , message="Bad email")
    private String email = null;
    @Min(value = 18)
    @Max(value = 99)
    private Integer age;


	/*
	 * This function Called once the bean is initialized in the memory 
	 */
	@PostConstruct
    public void init() {
		//System.out.println("*****  in init()*****");
		//   Do the following steps, 
		//1- Create empty Sale master object (with sysdate default) to be used in the sale.xhtml page
		//2- Create list of details contains Only one empty saleLine has the master sale object.
		//3- Prepare the needed list of data like Items for further usege
		
		prepareData();
		items = itemsFacade.findAll();// called once in init
		setSaleSavingStatus("false");
		
    }
    
	public int getView_no_counter() {
		return view_no_counter;
	}

	public void setView_no_counter(int view_no_counter) {
		this.view_no_counter = view_no_counter;
	}

	
	public boolean isValid()
	{
		return true ;
		
	}
	
	
	public void prepareData()
	{
		view_no_counter = 1 ;
	  	sale = new Sale();
	  	User user = usersFacade.find(2);
		sale.setCreateUser(user);
		sale.setLastModifyUser(user);
		Name name = nameFacade.find(1);
		sale.setNameId(name);
		
		saleLine = new SaleLine();
		saleLine.setSaleId(sale); // add the master sale object
		saleLine.setViewNo(view_no_counter);
		salesLines = new ArrayList<SaleLine>();
		salesLines.add(saleLine);
		
	}
	
	
	public List<Item> autocomplete(String prefix) 
	{
		System.out.println("prefix = '"+prefix+"'");
		List<Item> result = new ArrayList<Item>();
		for (Item item : getItems()) 
		{
			String suggestion = (item.getCode() + " " + item.getName()).toLowerCase() ;
			if (suggestion.contains(prefix.toLowerCase()))
			{
			   result.add(item);
		    }
		}
		return result;
	 }
	
	
	//1- Validate
	//2- set saleLines in the Master Sale object with conversion to Set
	//3- save to DB by calling the session Bean
	//4- reset and prepare data valeus
	//5  add confirmation messege.
	public void insertSale()
	{
		try
		{

		System.out.println ("begin") ;
		setSaleSavingStatus("false");

		if(isValid())
		{
			//System.out.println("adding line");
			//System.out.println(sale.getNote()+"-"+sale.getJvNo()+"-"+sale.getTotal());
			Set set = new HashSet(salesLines) ;
			System.out.println("***  set size = " + set.size());
			sale.setSaleLinesList(set);
			System.out.println("before saving");
			saleFacade.create(sale);
			System.out.println("after saving");
			setSaleSavingStatus("true");
			prepareData();
			//setSucceeded(true);
			System.out.println("data prepared");
		}
		}
		catch(Exception e )
		{
			e.printStackTrace();
		}
	}
	
	
	public void insertSale_test()
	{
		//System.out.println("begin saving the Sale");
		if(isValid())
		{
			//System.out.println("adding line");
			//System.out.println("***** "+ sale.getNote()+"-"+sale.getJvNo()+"-"+sale.getTotal());
			//sale.setSaleLinesList( new HashSet(salesLines));
			////System.out.println("before saving");
			saleFacade.create(sale);
			//System.out.println("data saved");
			prepareData();
			//System.out.println("data prepared");
		}
		else
		{
			
		}
	}
	
	public void insertSale_old()
	{
		try{
		Sale sale2 = new Sale();
		//System.out.println("before saving");
		saleFacade.create(sale2);
		//System.out.println("done saving");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	public void cancelSale()
	{
		setSaleSavingStatus("false");	
		prepareData();
	}

	
	
	
	public void addNewLineInDataTable()
	{
		/*//System.out.println("lineNumber: " + (salesLineslist.isEmpty() ? 1 : salesLineslist.get(salesLineslist.size() - 1).getId() + 1));
		SaleLine saleLine = new SaleLine();
		saleLine.setId(salesLineslist.isEmpty() ? 1 : salesLineslist.get(salesLineslist.size() - 1).getId() + 1);
		salesLineslist.add(saleLine);
		saleLine = new SaleLine(); // Reset placeholder.
		
		
		//System.out.println(sale.getNote()) ;
		/// //System.out.println(sale.getJvNo()) ;
		for (SaleLine sl : salesLines) {
			//System.out.println( sl.getItemId()) ;
			//System.out.println( sl.getQuantity()) ;
		}
		*/
	///	//System.out.println("** new Line to be added*");
		
		saleLine = new SaleLine();
		saleLine.setSaleId(sale); // add the master sale object
		saleLine.setViewNo(++view_no_counter);
		saleLine.setDiscount(0d);
		saleLine.setItemPrice(0d);
		
		salesLines.add(saleLine);
	}
	
    public void add() {
        // dao.create(item);
        // Actually, the DAO should already have set the ID from DB. This is just for demo.
        item.setId(items.isEmpty() ? 1 : items.get(items.size() - 1).getId() + 1);
        items.add(item);
        item = new Item(); // Reset placeholder.
    }

    public SaleLine getCurrentRow()
    {
    	FacesContext context = FacesContext.getCurrentInstance();
    	return (SaleLine)context.getApplication().evaluateExpressionGet(context, "#{line}", SaleLine.class);
    }
    
    
    public void updateRowData()
    {
    	currentSaleLine = getCurrentRow();
    	//currentSaleLine = null ;
    	//currentSaleLine = (SaleLine)getModel().getRowData();
    	////System.out.println("datamodel index = " + getModel().getRowCount() + " " + getModel().getRowIndex()) ;
    	if(currentSaleLine != null && currentSaleLine.getItemId() != null )
         {
    		 currentSaleLine.setItemPrice(currentSaleLine.getItemId().getItemDefEndUserPrice());
	         currentSaleLine.setPl(currentSaleLine.getItemId().getItemDefEndUserPrice());
	         currentSaleLine.setQuantity(1d); 
	         currentSaleLine.setNetValue(currentSaleLine.getItemPrice() *  currentSaleLine.getQuantity()) ;
	         calculateTotalValue();
	         calculateCashValue();
         }
    }
    
    public void adjustNetValue(AjaxBehaviorEvent event)
    {
    	//currentSaleLine = getModel().getRowData();
    	currentSaleLine = getCurrentRow();
    	currentSaleLine.setNetValue(currentSaleLine.getItemPrice() *  currentSaleLine.getQuantity()) ;
    	calculateTotalValue();
    	calculateCashValue();
    }
   
    
    public void visaValueVhange()
    {
       	if(sale.getVisa()==null) sale.setVisa(0d);
    	if(sale.getCredit()==null) sale.setCredit(0d);
    	if(sale.getCash()==null) sale.setCash(0d);
    	System.out.println("visa= "+sale.getVisa());
    	double cash = sale.getTotal() - sale.getVisa() - sale.getCredit() ;
    	System.out.println("cash= "+cash);
    	sale.setCash(cash) ;
    	if(cash >= 0)
    	{
    		sale.setCash(cash) ;	
    	}
    	else
        {
    	  	sale.setCash(0d);
    		double credit = sale.getTotal() - sale.getVisa() - sale.getCash() ;
    		sale.setCredit(credit);
        }
    }
    
    public void creditValueVhange()
    {
    	if(sale.getVisa()==null) sale.setVisa(0d);
    	if(sale.getCredit()==null) sale.setCredit(0d);
    	if(sale.getCash()==null) sale.setCash(0d);
    	double cash = sale.getTotal() - sale.getVisa() - sale.getCredit() ;
    	if(cash >= 0)
    	{
    		sale.setCash(cash) ;	
    	}
    	else
        {
    		double visa = sale.getTotal() - sale.getCredit() - sale.getCash() ;
    		sale.setVisa(visa);
        }
    }
    
    public void cashValueVhange()
    {
    	
    }
    
    
    public void calculateTotalValue()
    {
    	double total = 0 ;
    	for(SaleLine saleLine : salesLines)
    	{
    		if(saleLine.getItemId()!=null && saleLine.getItemPrice()!= null && saleLine.getItemPrice() > 0 )
    		{
    			total = total + (saleLine.getItemPrice() * saleLine.getQuantity()) ; 
    		}
    	}
    	sale.setTotal(total);
    }
    
    
    public void calculateCashValue()
    {
    	//if(sale.getTotal()== null) sale.setTotal(0);
    	if(sale.getVisa()==null) sale.setVisa(0d);
    	if(sale.getCredit()==null) sale.setCredit(0d);
    	
    	double cashValue = (sale.getTotal() - sale.getVisa() - sale.getCredit()) ;
    	if(cashValue < 0 )
    	{
    		cashValue = 0 ;
    	}
    	sale.setCash(cashValue) ;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    public boolean isSavedSuccessfully()
    {
    	return true ;
    }
    
    
    /*
    public void edit() {
        currentSaleLine = model.getRowData();
        edit = true;
    }*/

    public void save() {
        // dao.update(item);
        item = new Item(); // Reset placeholder.
        edit = false;
    }

    
    public void setList(List<Item> items) {
		this.items = items;
	}

	public void setModel(DataModel<SaleLine> model) {
		this.model = model;
	}

	public void setItem(Item item) {
		this.item = item;
	}

	public void setEdit(boolean edit) {
		this.edit = edit;
	}
    
	/*public void delete() {
        // dao.delete(item);
    	items.remove(model.getRowData());
    }*/

    public List<Item> getList() {
        return items;
    }

    public DataModel<SaleLine> getModel() {
       if (model == null) {
            model = new ListDataModel<SaleLine>(salesLines);
            //System.out.println(model.getRowCount() + " was null and populated" );
        }
       //System.out.println(model.getRowCount() + " returned" );
        return model;
    }

    public Item getItem() {
    	return item;
    }

    public boolean isEdit() {
        return edit;
    }

    private HtmlDataTable dataTable;

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }

	public float getTotal() {
		return total;
	}

	public void setTotal(float total) {
		this.total = total;
	}

	public Sale getSale() {
		return sale;
	}

	public void setSale(Sale sale) {
		this.sale = sale;
	}

	public SaleLine getSaleLine() {
		return saleLine;
	}

	public void setSaleLine(SaleLine saleLine) {
		this.saleLine = saleLine;
	}

	public List<SaleLine> getSalesLines() {
		return salesLines;
	}

	public void setSalesLines(List<SaleLine> salesLines) {
		this.salesLines = salesLines;
	}

	public List<Item> getItems() {
		return items;
	}

	public void setItems(List<Item> items) {
		this.items = items;
	}
    
    public String getSaleSavingStatus() {
		return saleSavingStatus;
	}

	public void setSaleSavingStatus(String saleSavingStatus) {
		this.saleSavingStatus = saleSavingStatus;
	}
    
	public SaleLine getCurrentSaleLine() {
		return currentSaleLine;
	}

	public void setCurrentSaleLine(SaleLine currentSaleLine) {
		this.currentSaleLine = currentSaleLine;
	}


	
	
	
    // Other getters/setters are actually unnecessary. Feel free to add them though.

}
